package com.pro5.test.pro5demo.service;

import com.pro5.test.pro5demo.domain.Pro5Goods;
import com.pro5.test.pro5demo.dto.PageResult;
import com.pro5.test.pro5demo.search.GoodsRepository;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.DoubleTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by fangjicai on 2020/1/3.
 */

@Service
public class SearchService {

    @Autowired
    private GoodsRepository goodsRepository;

    public PageResult<Pro5Goods> search(String keywords, BigDecimal priceRange,Integer page) {
        //1.创建原生查询构建对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.keywords创建匹配查询
        if(StringUtils.isNotBlank(keywords)){
            //TODO 分词查询
            MatchQueryBuilder keywordQuery = QueryBuilders.matchQuery("all", keywords).operator(Operator.AND);
            boolQuery = boolQuery.must(keywordQuery);
            // builder.withQuery(keywordQuery);
        }
        //3.价格范围查询
        BigDecimal begin= new BigDecimal(0);
        if(priceRange.doubleValue() > 2000 && priceRange.doubleValue()<=8000){
             begin = priceRange.subtract(new BigDecimal(2000));
            RangeQueryBuilder range = QueryBuilders.rangeQuery("price").
                    from(begin.doubleValue()).to(priceRange.doubleValue());
            boolQuery= boolQuery.filter(range);
                 //builder.withQuery(range);
        }else{
            //大于8000的 则条件为gt 8000以上
            RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gt(priceRange.doubleValue());
            //builder.withQuery(price);
            boolQuery= boolQuery.filter(price);
        }

        builder.withQuery(boolQuery);
        //4. 分页查询
        int pageSize=5;
        builder.withPageable(PageRequest.of(page-1,pageSize));
        //5.封装Pageresult对象
        Page<Pro5Goods> searchPage = goodsRepository.search(builder.build());
        PageResult<Pro5Goods> result = new PageResult<>();
        result.setContent(searchPage.getContent());
        result.setTotal(new Long(searchPage.getTotalPages()).intValue());
        result.setTotalPage(searchPage.getTotalPages());
        //TODO totalPage
        //6.返回
        return result;
    }

    public List<Map<String, Object>> getAggBrand() {
        //1.根据品牌聚合 StringTerm
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //去除hits
        builder.withSourceFilter(new FetchSourceFilter(new String[]{""},null));
       //2.subAgg 子聚合 DoubleTerm myBrand为聚合名称 terms 聚合的类型 brand 聚合的条件
        TermsAggregationBuilder aggregation = AggregationBuilders.terms("myBrand").field("brand").
                subAggregation(AggregationBuilders.avg("myPrice").field("price"));
        builder.addAggregation(aggregation);
        //3.获取AggregationPage 进而获取bucket 通
        AggregatedPage<Pro5Goods> page= (AggregatedPage<Pro5Goods>)this.goodsRepository.search(builder.build());
        //获取brand聚合结果
        StringTerms myBrand = (StringTerms) page.getAggregation("myBrand");
        List<StringTerms.Bucket> buckets = myBrand.getBuckets();
        List<Map<String, Object>> result = new ArrayList<>();
        for (StringTerms.Bucket bucket : buckets) {
            Map<String, Object> map = new HashMap<>();
            String brand = bucket.getKeyAsString();
            map.put("brand",brand);
            long num = bucket.getDocCount();
            map.put("num",num);
            Aggregations aggregations = bucket.getAggregations();
            InternalAvg myPrice = (InternalAvg) aggregations.asMap().get("myPrice");
            double value = myPrice.getValue();
            map.put("avg",value);
            result.add(map);
        }
        return result;
    }
}
